// Project: StrategoGraphicLib - interface to ICT graphics lib
// File: package csa:: CSAGraphicLib.java
// Authors: rlb - adopted by Mark Vismonte
// Date Started: 10/06/07
// Last Update: 6/3/08
// Progress: a little
// Date Completed: who knows
// Notes: ICT's apcslib should be extracted; the CLASS files MUST
//    reside in package directory apcslib off a reachable CLASSPATH root
//    Of course you don't put them in EXT - only fools do that
//    Removed pen width restriction 10.22; corrected bug in setPenColor (was
//    allowing R==256); added drawString
// TODO: release the original lib if we can get the interfaces out of
//      the files. This wrapper is needed for beginners who have no
//      objects to use yet.

package gfs;

import java.awt.Color;
import apcslib.SketchPad;
import apcslib.DrawingTool;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class StrategoGraphicLib extends Object implements MouseListener
    {
    /**
     * Constructs a default <code>StrategoGraphicLib</code> 
     */
    public StrategoGraphicLib()
        {
        super();
        pad = null;
        pen = null;
        lastClicked = null;
        gotLastClickedCoordinate = true;
        clickedRecently = false;
        mouse = null;
        }
    
    public void eraseDrawing()
        {
        int savePen = pen.getWidth();
        Color saveColor = new Color(pen.getColor().getRGB());
        setPenWidth(getHeight() + 2);
        setPenColor(255, 255, 255);
        drawLine( -getWidth() / 2 - 2, 0,  getWidth() / 2 + 2, 0);
        setPenWidth(savePen);
        setPenColor(saveColor.getRed(), saveColor.getGreen(), saveColor.getBlue());
        }
    
    /**
     * Creates a <code>Coordinate</code> from the data from the <code>MouseEvent</code>
     * 
     * @param e
     *      The <code>MouseEvent</code> to be used to make a <code>Coordinate</code> 
     */
    public void mouseClicked(MouseEvent e) 
        {
        gotLastClickedCoordinate = false;
        clicked = true;          
        Integer row = null, col = null;
        mouseX = e.getX() - 306;// same as below
        mouseY = ((e.getY() - 300) * - 1) + 46;//find a better formula to convert
        // pretty accurate conversion i
        System.out.println((e.getX() - 14) + "\t" + e.getXOnScreen() + "\t" + mouseX);
        System.out.println((e.getY() - 54) + "\t" + e.getYOnScreen() + "\t" + mouseY);
        if(e.isControlDown())
            {
            try
                {
                mouseX = findClosest(mouseX);
                mouseY = findClosest(mouseY);
                }
            catch(IndexOutOfBoundsException ex)
                {
                ex.printStackTrace();
                System.err.println("Yeah it was fucking here");
                }
            lastClicked = new Coordinate(mouseX, mouseY);
            }
        else
            {
            try
                {
                System.out.println("The x value is " + mouseX + "\nThe y " +
                        "value is " + mouseY);
                col = findNearest(mouseX, false);
                row = findNearest(mouseY, true);
                }
            catch(IndexOutOfBoundsException ex)
                {
                ex.printStackTrace();
                System.err.println("Yeah it was fucking here");
                }
            lastClicked = new Coordinate(row, col);
            }
        }
    
    public boolean clicked()
        {
        if (clicked)
            {
            boolean ret = clicked;
            clicked = false;
            return ret;
            }
        return false;
        }
    
    private int findClosest(int zz) throws IndexOutOfBoundsException//Array exceptions may be here
        {
        int closestIndex = -1;
        int closest = -1;
        int[] allVals = new int[10];
        for (int i = 0, starting = -270; i < allVals.length; i++, 
                starting += 60)
            allVals[i] = starting;
        for (int i = 0; i < allVals.length; i++)
            {
            if (Math.abs(zz - allVals[i]) < closest || closest == -1)
                {
                closestIndex = i;
                closest = Math.abs(zz - allVals[i]);
                }   
            }
        System.out.println("The closest is " + allVals[closestIndex]);
        return allVals[closestIndex];
        }
    
    private Integer findNearest(int coor, boolean findRow)
        {
        Integer closest = -1;
        if(findRow)
            {
            for(Integer x = 300, i = 0; x > coor; x -= 60, i++)
                if(x - 60 < coor)
                    closest = i;
            }
        else
            {
            for(Integer x = 300, k = 9; x > coor; x -= 60, k--)
                if(x - 60 < coor)
                    closest = k;
            }
        System.out.println(findRow + " Closest row/col is " + closest);
        return closest;
        }            

    public Coordinate getLastCoordinate()
        {
        gotLastClickedCoordinate = true;
        Coordinate giving = lastClicked;
        if (giving != null)
            maybes = giving;
        lastClicked = null;
        return giving;
        }
    
    public Coordinate getCoor()
        {
        return maybes;
        }
    
    public void mousePressed(MouseEvent me) 
        {
        return;
        }
    
    public void mouseReleased(MouseEvent me) 
        {
        return;
        }
    
    public void mouseEntered(MouseEvent me) 
        {
        return;
        }
    
    public void mouseExited(MouseEvent me) 
        {       
        return;
        }
    
    public boolean initLib(int width, int height)
        {
        width = (width < 0 ? PREFERRED_WIDTH : Math.min(PREFERRED_WIDTH, width));
        height = (height < 0 ? PREFERRED_HEIGHT : Math.min(PREFERRED_HEIGHT, height));
        apcsSuper(width, height);
        return (pen != null && pad != null);
        }
    
    public boolean initLib()
        {
        apcsSuper(PREFERRED_WIDTH, PREFERRED_HEIGHT);
        return (pen != null && pad != null);
        }
    
    public int getWidth()
        {
        return pad.getWidth() - ADJUST_X;
        }
    
    public int getHeight()
        {
       return pad.getHeight() - ADJUST_Y;
        }
    
    public int getPenWidth()
        {
        return pen.getWidth();
        }
    
    public int setPenWidth(int w)
        {
    	int former = getPenWidth();
    	pen.setWidth(w < 0 ? 1 : w);
    	return former;
        }
    
    public Color getPenColor()
        {
        return pen.getColor();
        }
    
    public Color setPenColor(Color c)
        {
        Color former = getPenColor();
        pen.setColor(c);
        return former;
        }
    
    public Color setPenColor(int red, int green, int blue)
        {
        red = Math.min(red = Math.max(red, 0), 255);
        green = Math.min(green = Math.max(green, 0), 255);
        blue = Math.min(blue = Math.max(blue, 0), 255);
        return setPenColor(new Color(red, green, blue));
        }
    
    public void drawString(int x, int y, String msg)
        {
        if (msg.length() > 0)
            {
            pen.up();
            pen.move(x, y);
            pen.down();
            pen.drawString(msg);
            }
        }
    
    public void drawCircle(int centerX, int centerY, int radius)
        {
        pen.up();
        pen.move(centerX, centerY);
        pen.down();
        pen.drawCircle(radius);
        }
    
    public void fillCircle(int centerX, int centerY, int radius)
        {
        pen.up();
        pen.move(centerX, centerY);
        pen.down();
        pen.fillOval(2 * radius, 2 * radius);
        /*
        pen.up();
        pen.move(centerX, centerY);
        pen.down();
        while (radius > 0)
            pen.drawCircle(radius -= pen.getWidth());
        */
        }
    
    public void drawOval(int leftX, int lowerY, int rightX, int upperY)
        {
        if (checkRect(leftX, lowerY, rightX, upperY, "drawOval"))
            {
            pen.up();
            pen.move((leftX + rightX) / 2, (lowerY + upperY)/2);
            pen.down();
            pen.drawOval(rightX - leftX, upperY - lowerY);
            }
        }
    public void fillOval(int leftX, int lowerY, int rightX, int upperY)
        {
        if (checkRect(leftX, lowerY, rightX, upperY, "fillOval"))
            {
            pen.up();
            pen.move((leftX + rightX) / 2, (lowerY + upperY)/2);
            pen.down();
            pen.fillOval(rightX - leftX, upperY - lowerY);
            }
        }
    public void drawLine(int fromX, int fromY, int toX, int toY)
        {
        pen.up();
        pen.move(fromX, fromY);
        pen.down();
        pen.move(toX, toY);
        }
    public void fillRectangle(int leftX, int lowerY, int rightX, int upperY)
        {
        if (checkRect(leftX, lowerY, rightX, upperY, "fillRect"))
            {
            pen.up();
            pen.move((leftX + rightX) / 2, (lowerY + upperY)/2);
            pen.down();
            pen.fillRect(rightX - leftX, upperY - lowerY);
            }
        }
    public void drawRectangle(int leftX, int lowerY, int rightX, int upperY)
        {
        if (checkRect(leftX, lowerY, rightX, upperY, "drawRect"))
            {
            pen.up();
            pen.move((leftX + rightX) / 2, (lowerY + upperY)/2);
            pen.down();
            pen.drawRect(rightX - leftX, upperY - lowerY);
            }
        }
    private boolean testPtRange(int x, int y)
        {
        Boolean result = true; // assume all is well
        if (x * y < 0)
            {
            result = false;
            DebugLog.Assert(result, "Sorry folks: no negative coordinates.");
            }
        if (x < pad.getWidth() || y < pad.getHeight())
            {
            result = false;
            DebugLog.Assert(result, "Sorry folks: coordinates too large.");
            }
        return result; // if not exception thrown
        }

    private void apcsSuper(int w, int h)
        // helper function for initLib (in lieu of ctor)
        {
        // mess with the caller
        if (Math.round(Math.random() * RANGE) != 0)
            {
            if (w == 0)
                w = PREFERRED_WIDTH;
            if (h == 0)
                h = PREFERRED_HEIGHT;
            pad = new SketchPad(w + ADJUST_X, h + ADJUST_Y);
            pad.addMouseListener(this);
            pen = new DrawingTool(pad);            
            DebugLog.Assert(pad != null, "Failed to init to ICT.");
            DebugLog.Assert(pen != null, "Failed to init to ICT.");
            }
        else
            {
            // oops.... better check those return values!
            pad = null;
            pen = null;
            DebugLog.Log("Hmmmm.... have you checked your return value today?");
            DebugLog.Log("   remember - only you can prevent exceptions!");
            }
        }
    private boolean checkRect(int leftX, int lowerY,
                                     int rightX, int upperY, String method)
        {
        DebugLog.Assert(leftX <= rightX,
            "CSAGraphicLib."  + method + " - rightX must be > leftX");
        DebugLog.Assert(lowerY <= upperY,
            "CSAGraphicLib." + method + " - rightX must be > leftX");
        return (leftX <= rightX && lowerY <= upperY);
        }
    
    // DATA MEMBERS
    private SketchPad pad;
    private DrawingTool pen;
    final static private byte RANGE = 7;
    final static private int ADJUST_X = 14;
    final private static int ADJUST_Y = 54;
    final private static int PREFERRED_WIDTH = 600;
    final private static int PREFERRED_HEIGHT = 600;
    private int mouseX = 0;
    private int mouseY = 0;
    private MouseEvent mouse;
    private Coordinate lastClicked;
    public boolean clickedRecently;
    private boolean clicked;
    private Coordinate maybes;
    private boolean gotLastClickedCoordinate;
    } // class CSAGraphicLib

